/** @constructor */
var createCssPxSocket = function(elem, prop_name){
	Socket.call(this);
	var oldSet = this.set;
	this.set = function(val){
		if (this.get()!=val){
			elem.style[prop_name] = val+'px';
			oldSet(val);
		}
	}
}

/** @constructor */
var createCssSocket = function(elem, prop_name){
	Socket.call(this);
	var oldSet = this.set;
	this.set = function(val){
		if (this.get()!=val){
			elem.style[prop_name] = val;
			oldSet(val);
		}
	}
}

/** @constructor */
var BoxCtrlImpl = function(){//handle on-demand sockets
	if ('click' in this.sockets){
		var out = this.sockets['click'];//signal
		var handler = function(){
			out.set({});//{} represent the signal, as it will always be a new value!
			console.log('click');
		}
		var clickIn = function(){
			var ret = new Socket();
			var v = null;
			ret.set = function(val){
				if (v==val) return;
				if (v)
					v.getElem().removeEventListener('click',handler, false);
				if (val)
					val.getElem().addEventListener('click', handler, false);
				v = val;
			}
			ret.get = function(){
				return v;
			}
			return ret;
		}();
		this.addOutput(clickIn);
	}
}

_registerCtrl('Box',{
	'x':'Number',
	'y':'Number',
	'width':'Number',
	'height':'Number',
	'background':'String',
	'click':'Signal'
},BoxCtrlImpl)

/** @constructor */
var BoxCtrl = function(elem){
	this['x'] = new createCssPxSocket(elem, 'left'),
	this['y'] = new createCssPxSocket(elem, 'top'),
	this['width'] = new createCssPxSocket(elem, 'width'),
	this['height'] = new createCssPxSocket(elem, 'height'),
	this['background'] = new createCssSocket(elem, 'background')
}

/** @constructor */
var WebObjectCtrl = function(elem){
	this['destroy'] = function(){
		elem.parentNode.removeChild(elem);
	}
}

var WebPanel = function(){
	var className = 'Panel';
	/** @constructor*/
	var ret = function(pPanel){
		var elem;
		elem = document.createElement('div');
		elem.className = 'webdiv';

		if (pPanel)
			pPanel.getElem().appendChild(elem);
		else
			_canvas.appendChild(elem);

		this.ctrls={
			'Box': new BoxCtrl(elem),
			'Object':new WebObjectCtrl(elem)
		},
		this.getElem=function(){
			return elem;
		}
	}
	ret.prototype._class = className;
	_registerClass(className, ret);
	return ret;
}();

var WebButton = function(){
	var className = 'Button';
	/** @constructor*/
	var ret = function(pPanel){
		var elem;
		elem = document.createElement('input');
		if (pPanel)
			pPanel.get().appendChild(elem);

		this.ctrls={
			'Box': new BoxCtrl(elem),
			'Object':new WebObjectCtrl(elem)
		},
		this.getElem=function(){
			return elem;
		}
	}
	ret.prototype._class = className;
	_registerClass(className, ret);
	return ret;
}();


var closure_workaround = function(){
	//to use _create function generation, do the following!
	_getReturnCode(function(){
		return _create;
	}.toString());//--> will return the id of _create after obfuscation! and this code is obfuscated too!
}

var protoA = function(){
	//from internal objects
	var _objs = [];
	var div = _create('Panel',[null]);//object referenced by infrared! identifier name comes from decl_id
	_objs.append(_create('Button',[div]));//unreferenced obj has no identifier --> it could have if it appears in constructor of other objs --> referenced in create plate!
	_objs.appends(div);
	//from power plate
	var divCtrl = _ctrl('Box',['x']);//controller uses a proto name
	divCtrl.output.add(div.input);//1 output can connect to multiple inputs. Box is compatible with Panel!
	div.output.add(divCtrl.input);
	divCtrl.box.x.set(50);//equivalent to div.x.set(50)
	var joyStick = _create('JoyStick');//joystick has no input!
	var joyCtrl = new JoyCtrl();
	joyStick.output.add(joyCtrl.input);
	joyCtrl.x.output.add(divCtrl.box.x.input);
	joyStick.x.set(4);//this set is inside JoyStick class
	//--> joyCtrl.x.set(4) --> divCtrl.x.set(4) --> div.x.set(4)

	//from controller, public properties are all here
	this['Box'] = function(){//expose the box controller of div
		var ret = _ctrl('Box')//controller uses a controller name
		ret.output.add(div.box.input);
		div.box.output.add(ret);
		return ret;
	};
	this['newCtrl'] = function(){
		var ret = _ctrl('newCtrl');//create new ctrl
		ret['bkg'] = _ctrl('Color');
		//ret['bkg'].output.add(div['Div']['bkg'].input);
		div['Div']['bkg'].output.add(ret['bkg'].input);//read only slot!
	}
}

var test2 = function(){
	var wifiSignal = new BroadcastImpl('Panel');

	var div2 = _create('Panel',[null]);
	div2.ctrls['Box']['x'].set(20);
	div2.ctrls['Box']['y'].set(20);
	div2.ctrls['Box']['width'].set(100);
	var div = _create('Panel',[null]);
	div.ctrls['Box']['background'].set('blue');

	var divCtrl = new _ctrlImpl('Box',['x']);
	divCtrl.groupConnect(wifiSignal);
	divCtrl.sockets['x'].set(3);//--> set all Panel x to 3!

	var desX = new NumberCtrlDesigner(divCtrl.sockets['x']);
	_plate.appendChild(desX.getElem());

	var divCtrl2 = new _ctrlImpl('Box',['y']);
	divCtrl2.staticConnect(div2);//only between two static ends
	var desY = new NumberCtrlDesigner(divCtrl2.sockets['y']);
	_plate.appendChild(desY.getElem());

	//var plateOut = new CtrlGroupImpl(['Box','Object'],['destroy']);
	var plateOut = new CtrlGroupImpl('Box');
	wifiSignal.addPlate(function(){
		var divCtrl = new _ctrlImpl('Box',['y']);
		divCtrl.connectReverse(this);
		//divCtrl.connect(this);//since 'this' could be removed from the group, dynamic connect is prefered
		//divCtrl.staticConnect(this);//they are static to each others!
		var nCtrl = new _ctrlImpl('Number',['greater']);
		divCtrl.sockets['y'].addOutput(nCtrl);
		//this.ctrls['Box']['y'].addOutput(nCtrl);
		var grpMiddleMan = new AdditiveSwitch(this, plateOut);
		nCtrl.sockets['greater']['another'].set(100);
		nCtrl.sockets['greater']['out'].addOutput(grpMiddleMan);
		return function(){//clean up function, only neccessary for non-wifi ctrlGroup, because object can be removed without being deleted
			//this.ctrls['Box']['y'].removeOutput(nCtrl);
			//when use staticConnect, there are more things to disconnect!
			divCtrl.sockets['y'].removeOutput(nCtrl);//divCtrl connect to 'this'. So all its connections need to be removed
			//TODO: disconnect the AdditiveSwitch! --> not neccessary
		}
	});
	//all panel with y>100 will become yellow!
	var outCtrl = new _ctrlImpl('Box',['background']);
	outCtrl.groupConnect(plateOut);
	outCtrl.sockets['background'].set('yellow');
}

var test3Decl = {
	objs:{
		'pan':{
			proto:'Panel',
			cons:[null],
			adjustments:{
				'Box':{
					'background':'blue'
				}
			}
		}
	},
	srcs:{
		'pan':[ ['abc'] ]
	},
	ctrls:{
		'abc':{
			ctrl:'Box',
			sockets:{
				'x':[ ['def'] ],
				'y':[],
				'click':[]
			},
			outputs:[ ['pan'] ]
		},
		'def':{
			ctrl:'Number',
			sockets:{
				'sqr':[],
				'plus':{
					'another':[],
					'out':[ ['abc','y'] ]
				}
			}
		}
	}
}

var test3 = function(){
	var wifi = new BroadcastImpl('Panel');//need to be put before any _create statement!

	var div2 = _create('Panel',[null]);
	div2.ctrls['Box']['x'].set(20);
	div2.ctrls['Box']['y'].set(20);
	div2.ctrls['Box']['width'].set(100);

	var div = _create('Panel',[null]);
	div.ctrls['Box']['background'].set('blue');
	var divCtrl = new _ctrlImpl('Box',['x','y','click']);

	divCtrl.groupConnect(wifi);
	//divCtrl.connect(div);//all outputs from divCtrl will be forwarded to div

	divCtrl.set(div);//all on-demand sockets from div will trigger sockets in divCtrl

	//divCtrl.sockets['x'].addOutput(divCtrl.sockets['y']);
	var nCtrl = new _ctrlImpl('Number',['sqr','plus']);
	divCtrl.sockets['x'].addOutput(nCtrl);

	nCtrl.sockets['plus']['out'].addOutput(divCtrl.sockets['y']);

	var desX = new NumberCtrlDesigner(divCtrl.sockets['x']);
	_plate.appendChild(desX.getElem());
	var desAnother = new NumberCtrlDesigner(nCtrl.sockets['plus']['another']);
	_plate.appendChild(desAnother.getElem());
	var desY = new NumberCtrlDesigner(divCtrl.sockets['y']);
	_plate.appendChild(desY.getElem());
	var desSqr = new NumberCtrlDesigner(nCtrl.sockets['sqr']);
	_plate.appendChild(desSqr.getElem());


	divCtrl.sockets['x'].set(30);
	nCtrl.sockets['plus']['another'].set(23);
	//div.ctrls['Box']['y'].set(30);
}

rootload = function(){
	test2();
	console.log(_parseProtoDecl(test3Decl));


	//test responsiveness
	var btn = document.createElement('input');
	btn.type = 'button';
	btn.value = 'test';
	btn.addEventListener('click',function(){
		alert('abc');
	},false);
	_log.appendChild(btn);
	//hang the script here
	/*
	var conti = true;
	var count = 0;
	var t = setInterval(function(){
		if (!conti) return;
		_log.innerHTML = count++;
	},1);
	//*/
}
